home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1996 April
/
EnigmA AMIGA RUN 06 (1996)(G.R. Edizioni)(IT)[!][issue 1996-04][Skylink CD V].iso
/
earcd
/
utilgfx
/
raylab.lha
/
RayLab
/
source
/
raylab.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-02-16
|
18KB
|
539 lines
/*
name: raylab.c
Main program
------------
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "defs.h"
#include "getworld.h"
#include "tga.h"
/* Global variables (most mentioned in extern.h) */
long PicWidth, PicHeight, RecDepth, NumObjects, NumLights;
CAMERA Camera;
COLOR BackgroundColor;
long AntiAliasingRec;
double AntiAliasingThreshold, AntiAliasingJitter;
long ReqDisplayType, GotDisplayType;
OBJECT *ObjectArray[maxobjects];
LIGHT *LightArray[maxlights];
unsigned char pixlearray[parraysize];
long picturerendering;
long PlaneIntersectionAttempts,PlaneIntersections;
long SphereIntersectionAttempts,SphereIntersections;
long EllipsoidIntersectionAttempts,EllipsoidIntersections;
long TriangleIntersectionAttempts,TriangleIntersections;
long BoxIntersectionAttempts,BoxIntersections;
long DiscIntersectionAttempts,DiscIntersections;
long CylinderIntersectionAttempts,CylinderIntersections;
long ShadowAttempts,ShadowHits,ReflectedRays;
FILE *inputfile,*outputfile;
long outfileopen,objectalloc,aalinbufalloc,displayopen;
/* Declaration of entries in the anti-aliasing table(s) */
typedef struct AAEntry_Struct AAENTRY;
struct AAEntry_Struct {
COLOR Color;
unsigned char Done;
};
AAENTRY aatable[aamaxlevel][aamaxlevel]; /* 9x9 matrix <=> max rec.-level: 4 */
AAENTRY *aalinebuffer; /* Line-buffer for major speedup during antialiasing */
/**********************************************************************
*
* main()
*
**********************************************************************/
void main(int argc, char *argv[])
{
time_t starttrace, endtrace;
int spenttime, spent_h, spent_m, spent_s;
outfileopen=objectalloc=aalinbufalloc=displayopen=picturerendering=0;
fprintf(stderr,"RayLab v1.0 (c)1995-1996 by Marcus Geelnard\n");
fprintf(stderr,"-------------------------------------------\n");
if(argc<3) {
fprintf(stderr,"\n*** Not enough parameters!\n");
fprintf(stderr,"Usage: %s <input file> <output file>\n",argv[0]);
exit(0);
}
if(CreateWorld(argv[1])!=0) { /* Do some world-declarations */
exit(1);
}
objectalloc=1;
if((outputfile=fopen(argv[2],"wb"))==NULL) {
fprintf(stderr,"\n*** Could not open output file!\n");
cleanup();
exit(1);
}
else outfileopen=1;
if(AntiAliasingRec>=1L) {
if((aalinebuffer=(AAENTRY *)calloc((size_t)(PicWidth*aamaxlevel),sizeof(AAENTRY)))==NULL) {
fprintf(stderr,"\n*** Could not allocate memory for antialiasing line buffer!\n");
cleanup();
exit(1);
}
else {
fprintf(stderr,"(Allocated %ld KB of memory for antialiasing line buffer)\n\n",(long)(PicWidth*aamaxlevel*(long)sizeof(AAENTRY))/(long)1024);
aalinbufalloc=1;
}
}
fprintf(stderr,"Image size: %ldx%ld\n",PicWidth,PicHeight);
WriteTgaHeader(outputfile,PicWidth,PicHeight);
fprintf(stderr,"\nLights: %ld\n",NumLights);
fprintf(stderr,"Primitives: %ld\n\n",NumObjects);
PlaneIntersectionAttempts = PlaneIntersections = 0;
SphereIntersectionAttempts = SphereIntersections = 0;
EllipsoidIntersectionAttempts = EllipsoidIntersections = 0;
DiscIntersectionAttempts = DiscIntersections = 0;
CylinderIntersectionAttempts = CylinderIntersections = 0;
ShadowAttempts=ShadowHits = 0;
ReflectedRays = 0;
GotDisplayType = OpenDisplay(ReqDisplayType); /* Open potential display */
displayopen=1;
time(&starttrace);
picturerendering=1;
ScanWorld(); /* Make the actual ray-tracing */
picturerendering=0;
time(&endtrace);
spenttime=(int)difftime(endtrace,starttrace);
spent_h=spenttime/(60*60);
spent_m=(spenttime%(60*60))/60;
spent_s=spenttime%60;
fprintf(stderr,"\nDone!\n\n");
fprintf(stderr,"Shape Tests Hits\n");
fprintf(stderr,"-----------------------------------------------\n");
if(PlaneIntersectionAttempts>0)
fprintf(stderr,"Plane %10ld %10ld (%3.2lf%%)\n",PlaneIntersectionAttempts,PlaneIntersections,((double)PlaneIntersections/(double)PlaneIntersectionAttempts)*100.0);
if(SphereIntersectionAttempts>0)
fprintf(stderr,"Sphere %10ld %10ld (%3.2lf%%)\n",SphereIntersectionAttempts,SphereIntersections,((double)SphereIntersections/(double)SphereIntersectionAttempts)*100.0);
if(EllipsoidIntersectionAttempts>0)
fprintf(stderr,"Ellipsoid %10ld %10ld (%3.2lf%%)\n",EllipsoidIntersectionAttempts,EllipsoidIntersections,((double)EllipsoidIntersections/(double)EllipsoidIntersectionAttempts)*100.0);
if(TriangleIntersectionAttempts>0)
fprintf(stderr,"Triangle %10ld %10ld (%3.2lf%%)\n",TriangleIntersectionAttempts,TriangleIntersections,((double)TriangleIntersections/(double)TriangleIntersectionAttempts)*100.0);
if(BoxIntersectionAttempts>0)
fprintf(stderr,"Box %10ld %10ld (%3.2lf%%)\n",BoxIntersectionAttempts,BoxIntersections,((double)BoxIntersections/(double)BoxIntersectionAttempts)*100.0);
if(DiscIntersectionAttempts>0)
fprintf(stderr,"Disc %10ld %10ld (%3.2lf%%)\n",DiscIntersectionAttempts,DiscIntersections,((double)DiscIntersections/(double)DiscIntersectionAttempts)*100.0);
if(CylinderIntersectionAttempts>0)
fprintf(stderr,"Cylinder %10ld %10ld (%3.2lf%%)\n",CylinderIntersectionAttempts,CylinderIntersections,((double)CylinderIntersections/(double)CylinderIntersectionAttempts)*100.0);
fprintf(stderr,"\nShadow rays: tested: %ld blocked: %ld (%2.2lf%%)\n",ShadowAttempts,ShadowHits,100.0*(double)ShadowHits/(double)ShadowAttempts);
fprintf(stderr,"Reflected rays: %ld\n",ReflectedRays);
fprintf(stderr,"\nTime: %dh %dmin %ds\n\n",spent_h,spent_m,spent_s);
/* if(AntiAliasingRec>=1L) {
free(aalinebuffer);
}
FreeAllObjectMemory();
fclose(outputfile);
*/
cleanup();
exit(0);
}
/**********************************************************************
*
* cleanup() cleans up the system, closes down things etc...
*
**********************************************************************/
void cleanup(void) {
if(outfileopen==1) {
fclose(outputfile);
outfileopen=0;
}
if(aalinbufalloc==1) {
free(aalinebuffer);
aalinbufalloc=0;
}
if(displayopen==1) {
CloseDisplay(); /* Close display (if any was opened) */
displayopen=0;
}
if(objectalloc==1) {
FreeAllObjectMemory(); /* Free memory that was allocated for objects */
objectalloc=0;
}
}
/**********************************************************************
*
* ScanWorld() is the main tracing routine
*
**********************************************************************/
void ScanWorld(void)
{
long column,line;
COLOR ReturnColor;
LINE ScanLine;
POINT CameraLocation,ScreenLocation,OldScreenLocation;
VECTOR vtemp,vxstep,vystep;
int i,j;
unsigned char RGBColor[3];
AAENTRY *currentlinebufentry,*currentlinebufentry_tmp;
CreatePoint(&CameraLocation,Camera.Location.x,Camera.Location.y,Camera.Location.z);
CopyPoint(&ScreenLocation,&CameraLocation);
ScaleVector(&vtemp,Camera.Aspect.z,&(Camera.Direction));
ScreenLocation.x+=vtemp.x; ScreenLocation.y+=vtemp.y; ScreenLocation.z+=vtemp.z;
ScaleVector(&vtemp,(Camera.Aspect.y)/(double)2,&(Camera.Up));
ScreenLocation.x+=vtemp.x; ScreenLocation.y+=vtemp.y; ScreenLocation.z+=vtemp.z;
ScaleVector(&vtemp,(Camera.Aspect.x)/(double)2,&(Camera.Right));
ScreenLocation.x-=vtemp.x; ScreenLocation.y-=vtemp.y; ScreenLocation.z-=vtemp.z;
ScaleVector(&vxstep,(Camera.Aspect.x)/(double)PicWidth,&(Camera.Right));
ScaleVector(&vystep,-(Camera.Aspect.y)/(double)PicHeight,&(Camera.Up));
if(AntiAliasingRec>=1L) {
currentlinebufentry=aalinebuffer;
for(column=0;column<PicWidth;column++) { /* Clear antialiasing line-buffer */
for(i=0;i<aamaxlevel;i++) {
currentlinebufentry->Done=0;
currentlinebufentry++;
}
}
}
for(line=1;line<=PicHeight;line++) {
if(AntiAliasingRec>=1L) {
for(i=0;i<aamaxlevel;i++) {
for(j=0;j<aamaxlevel;j++) {
aatable[i][j].Done=0; /* Clear whole aatable */
}
}
currentlinebufentry=aalinebuffer;
}
CopyPoint(&OldScreenLocation,&ScreenLocation);
fprintf(stderr,"\rRendering line %ld of %ld (%3.1lf%%)",line,PicHeight,100.0*(double)line/(double)PicHeight);
for(column=1;column<=PicWidth;column++) {
if(AntiAliasingRec<1L) {
MakeLine(&ScanLine,&CameraLocation,&ScreenLocation);
(void) TraceRay(&ReturnColor,&ScanLine,RecDepth);
}
else {
for(j=0;j<aamaxlevel;j++) { /* Copy right column of last scan to left column of new scan! */
if((aatable[0][j].Done=aatable[aamaxlevel-1][j].Done)!=0)
CopyColor(&aatable[0][j].Color,&aatable[aamaxlevel-1][j].Color);
}
currentlinebufentry_tmp=currentlinebufentry;
for(i=0;i<aamaxlevel;i++) { /* Copy top row from previous line */
if((aatable[i][0].Done=currentlinebufentry->Done)!=0)
CopyColor(&aatable[i][0].Color,¤tlinebufentry->Color);
currentlinebufentry++;
}
for(i=1;i<aamaxlevel;i++) {
for(j=1;j<aamaxlevel;j++) {
aatable[i][j].Done=0; /* Clear rest of aatable */
}
}
ScanOnePoint(&ReturnColor,&CameraLocation,&ScreenLocation,&vxstep,&vystep,0,aamaxlevel-1,0,aamaxlevel-1,AntiAliasingRec);
currentlinebufentry=currentlinebufentry_tmp;
for(i=0;i<aamaxlevel;i++) { /* Save bottom row for next line */
if((currentlinebufentry->Done=aatable[i][aamaxlevel-1].Done)!=0)
CopyColor(¤tlinebufentry->Color,&aatable[i][aamaxlevel-1].Color);
currentlinebufentry++;
}
}
RGBColor[0] = (unsigned char)(255*ReturnColor.r);
RGBColor[1] = (unsigned char)(255*ReturnColor.g);
RGBColor[2] = (unsigned char)(255*ReturnColor.b);
pixlearray[(column-1)*3+0] = RGBColor[0];
pixlearray[(column-1)*3+1] = RGBColor[1];
pixlearray[(column-1)*3+2] = RGBColor[2];
if(GotDisplayType!=0L)
DisplayPlot((int)(column-1),(int)(line-1), RGBColor);
ScreenLocation.x+=vxstep.x;
ScreenLocation.y+=vxstep.y;
ScreenLocation.z+=vxstep.z;
}
WriteTgaLine(outputfile,PicWidth);
CopyPoint(&ScreenLocation,&OldScreenLocation);
ScreenLocation.x+=vystep.x;
ScreenLocation.y+=vystep.y;
ScreenLocation.z+=vystep.z;
}
}
void ScanOnePoint(COLOR *Color, POINT *CameraLocation, POINT *ScreenLocation, VECTOR *dx, VECTOR *dy, int ColumnFirst, int ColumnLast, int RowFirst, int RowLast, long AARec)
{
LINE ScanLine;
POINT ScreenLocation2;
VECTOR dx2,dy2;
COLOR ReColor[4],MinColor,MaxColor;
double ColorDiff;
int i, DeltaColumn, DeltaRow;
if(aatable[ColumnFirst][RowFirst].Done==0) {
MakeLine(&ScanLine,CameraLocation,ScreenLocation);
(void) TraceRay(&ReColor[0],&ScanLine,RecDepth);
aatable[ColumnFirst][RowFirst].Done=1;
CopyColor(&aatable[ColumnFirst][RowFirst].Color,&ReColor[0]);
}
else {
CopyColor(&ReColor[0],&aatable[ColumnFirst][RowFirst].Color);
}
AddVector((VECTOR *)&ScreenLocation2,(VECTOR *)ScreenLocation,dx);
if(aatable[ColumnLast][RowFirst].Done==0) {
MakeLine(&ScanLine,CameraLocation,&ScreenLocation2);
(void) TraceRay(&ReColor[1],&ScanLine,RecDepth);
aatable[ColumnLast][RowFirst].Done=1;
CopyColor(&aatable[ColumnLast][RowFirst].Color,&ReColor[1]);
}
else {
CopyColor(&ReColor[1],&aatable[ColumnLast][RowFirst].Color);
}
AddVector((VECTOR *)&ScreenLocation2,(VECTOR *)&ScreenLocation2,dy);
if(aatable[ColumnLast][RowLast].Done==0) {
MakeLine(&ScanLine,CameraLocation,&ScreenLocation2);
(void) TraceRay(&ReColor[2],&ScanLine,RecDepth);
aatable[ColumnLast][RowLast].Done=1;
CopyColor(&aatable[ColumnLast][RowLast].Color,&ReColor[2]);
}
else {
CopyColor(&ReColor[2],&aatable[ColumnLast][RowLast].Color);
}
SubVector((VECTOR *)&ScreenLocation2,(VECTOR *)&ScreenLocation2,dx);
if(aatable[ColumnFirst][RowLast].Done==0) {
MakeLine(&ScanLine,CameraLocation,&ScreenLocation2);
(void) TraceRay(&ReColor[3],&ScanLine,RecDepth);
aatable[ColumnFirst][RowLast].Done=1;
CopyColor(&aatable[ColumnFirst][RowLast].Color,&ReColor[3]);
}
else {
CopyColor(&ReColor[3],&aatable[ColumnFirst][RowLast].Color);
}
if(AARec>1L) {
CopyColor(&MinColor,&ReColor[0]); /* Determine min/max values for r,g,b */
CopyColor(&MaxColor,&ReColor[0]);
for(i=1;i<4;i++) {
if(ReColor[i].r<MinColor.r) MinColor.r=ReColor[i].r;
else if(ReColor[i].r>MaxColor.r) MaxColor.r=ReColor[i].r;
if(ReColor[i].g<MinColor.g) MinColor.g=ReColor[i].g;
else if(ReColor[i].g>MaxColor.g) MaxColor.g=ReColor[i].g;
if(ReColor[i].b<MinColor.b) MinColor.b=ReColor[i].b;
else if(ReColor[i].b>MaxColor.b) MaxColor.b=ReColor[i].b;
}
ColorDiff=MaxColor.r-MinColor.r+MaxColor.g-MinColor.g+MaxColor.b-MinColor.b;
if(ColorDiff>AntiAliasingThreshold) {
ScaleVector(&dx2,0.5,dx);
ScaleVector(&dy2,0.5,dy);
DeltaColumn=(ColumnLast-ColumnFirst)>>1;
DeltaRow=(RowLast-RowFirst)>>1;
ScanOnePoint(&ReColor[0],CameraLocation,ScreenLocation,&dx2,&dy2,ColumnFirst,ColumnFirst+DeltaColumn,RowFirst,RowFirst+DeltaRow,AARec-1);
AddVector((VECTOR *)&ScreenLocation2,(VECTOR *)ScreenLocation,&dx2);
ScanOnePoint(&ReColor[1],CameraLocation,&ScreenLocation2,&dx2,&dy2,ColumnFirst+DeltaColumn,ColumnLast,RowFirst,RowFirst+DeltaRow,AARec-1);
AddVector((VECTOR *)&ScreenLocation2,(VECTOR *)&ScreenLocation2,&dy2);
ScanOnePoint(&ReColor[2],CameraLocation,&ScreenLocation2,&dx2,&dy2,ColumnFirst+DeltaColumn,ColumnLast,RowFirst+DeltaRow,RowLast,AARec-1);
SubVector((VECTOR *)&ScreenLocation2,(VECTOR *)&ScreenLocation2,&dx2);
ScanOnePoint(&ReColor[3],CameraLocation,&ScreenLocation2,&dx2,&dy2,ColumnFirst,ColumnFirst+DeltaColumn,RowFirst+DeltaRow,RowLast,AARec-1);
}
}
CopyColor(Color,&ReColor[0]);
for(i=1;i<4;i++) {
Color->r+=ReColor[i].r;
Color->g+=ReColor[i].g;
Color->b+=ReColor[i].b;
}
Color->r*=0.25; Color->g*=0.25; Color->b*=0.25;
}
/**********************************************************************
*
* TraceRay() will trace a given ray and return a resulting color
*
**********************************************************************/
long TraceRay(COLOR *Color, LINE *RayLine, long RecurseLevel)
{
double t,tnew,angle,dintense,pintense;
LINE LightLine,ReflectLine;
POINT IPoint;
VECTOR surfnormal,reflectvect;
COLOR surfcolor,ReflectedColor;
long i,ObjNum=-1;
/* Find closest hit */
if(RecurseLevel>0) {
t=-1;
for(i=0;i<NumObjects;i++) {
tnew=Intersect_Object(RayLine, ObjectArray[i]);
if((tnew>EPSILON)&&((tnew<t)||(t<=EPSILON))) {
ObjNum=i;
t=tnew;
}
}
/* Calculate color in intersected point */
if(ObjNum>=0) {
IPoint.x=RayLine->Origin.x+t*RayLine->Direction.x;
IPoint.y=RayLine->Origin.y+t*RayLine->Direction.y;
IPoint.z=RayLine->Origin.z+t*RayLine->Direction.z;
if(fabs(IPoint.x+IPoint.y+IPoint.z)>maxsumcoord) {
ObjNum=-1;
Color->r=BackgroundColor.r;
Color->g=BackgroundColor.g;
Color->b=BackgroundColor.b;
}
else {
GetSurfaceColor(&surfcolor, &ObjectArray[ObjNum]->Texture, &IPoint);
GetSurfaceNormal(&surfnormal, &IPoint, ObjectArray[ObjNum]);
angle=VectorsAngle(&surfnormal,&(RayLine->Direction));
if(angle<PID2) NegVector(&surfnormal,&surfnormal); /* So that the surface-normal always points towards us */
ReflectVector(&reflectvect,&(RayLine->Direction),&surfnormal);
Color->r=Color->g=Color->b=0.0;
for(i=0;i<NumLights;i++) {
dintense=0.0;
pintense=0.0;
MakeLine(&LightLine,&IPoint,&(LightArray[i]->Location));
if(TestShadowRay(&LightLine,ObjNum)<0) {
angle=VectorsAngle(&surfnormal,&(LightLine.Direction));
if(angle<PID2) {
dintense=ObjectArray[ObjNum]->Texture.Diffuse*cos(angle);
angle=VectorsAngle(&reflectvect,&(LightLine.Direction));
if(angle<PID2) {
pintense=ObjectArray[ObjNum]->Texture.Phong*pow(cos(angle),ObjectArray[ObjNum]->Texture.PhongSize);
}
}
}
dintense = (dintense > 1.0 ? 1.0 : dintense);
pintense = (pintense > 1.0 ? 1.0 : pintense);
Color->r+=((dintense*surfcolor.r+pintense)*LightArray[i]->Color.r);
Color->g+=((dintense*surfcolor.g+pintense)*LightArray[i]->Color.g);
Color->b+=((dintense*surfcolor.b+pintense)*LightArray[i]->Color.b);
}
Color->r+=surfcolor.r*ObjectArray[ObjNum]->Texture.Ambient;
Color->g+=surfcolor.g*ObjectArray[ObjNum]->Texture.Ambient;
Color->b+=surfcolor.b*ObjectArray[ObjNum]->Texture.Ambient;
if((ObjectArray[ObjNum]->Texture.Reflect.r+ObjectArray[ObjNum]->Texture.Reflect.g+ObjectArray[ObjNum]->Texture.Reflect.b)>EPSILON) {
ReflectedRays++;
CopyVector(&(ReflectLine.Direction),&reflectvect);
CopyPoint(&(ReflectLine.Origin),&IPoint);
TraceRay(&ReflectedColor, &ReflectLine, RecurseLevel-1L);
Color->r+=(ObjectArray[ObjNum]->Texture.Reflect.r*ReflectedColor.r);
Color->g+=(ObjectArray[ObjNum]->Texture.Reflect.g*ReflectedColor.g);
Color->b+=(ObjectArray[ObjNum]->Texture.Reflect.b*ReflectedColor.b);
}
Color->r = (Color->r > 1.0 ? 1.0 : Color->r);
Color->g = (Color->g > 1.0 ? 1.0 : Color->g);
Color->b = (Color->b > 1.0 ? 1.0 : Color->b);
}
}
else {
Color->r=BackgroundColor.r;
Color->g=BackgroundColor.g;
Color->b=BackgroundColor.b;
}
}
else {
Color->r=0.0; /* Return no color (= color black) if recursion- */
Color->g=0.0; /* level <= 0 */
Color->b=0.0;
}
return(ObjNum);
}
/**********************************************************************
*
* TestShadowRay() will trace a given ray and look for object-hits
*
**********************************************************************/
long TestShadowRay(LINE *RayLine, long CurrentObject)
{
long i,hit=-1;
double t,told=-1;
ShadowAttempts++;
for(i=0;i<NumObjects;i++) {
if(i!=CurrentObject) {
t=Intersect_Object(RayLine, ObjectArray[i]);
if((t>EPSILON)&&((t<told)||(told<=EPSILON))) {
hit=i;
told=t;
}
}
}
t=told;
if(t>1.0) hit=-1; /* Object was beyond light */
if(hit>=0) ShadowHits++;
return(hit);
}